import json
import time
import logging
import logging.handlers
import os
import sys
import platform
import shutil
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


'''
EVENTS:
watchdog.events.FileSystemEvent(src_path)
watchdog.events.FileSystemMovedEvent(src_path, dest_path)
watchdog.events.FileMovedEvent(src_path, dest_path)
watchdog.events.DirMovedEvent(src_path, dest_path)
watchdog.events.FileModifiedEvent(src_path)
watchdog.events.DirModifiedEvent(src_path)
watchdog.events.FileCreatedEvent(src_path)
watchdog.events.FileClosedEvent(src_path)
watchdog.events.DirCreatedEvent(src_path)
watchdog.events.FileDeletedEvent(src_path)
watchdog.events.DirDeletedEvent(src_path)

EVNETS HANDLER:
watchdog.events.FileSystemEventHandler
watchdog.events.PatternMatchingEventHandler
watchdog.events.RegexMatchingEventHandler
watchdog.events.LoggingEventHandler

OBSERVER:
watchdog.observers.api.ObservedWatch(path, recursive)
watchdog.observers.api.EventQueue(maxsize=0)
watchdog.observers.api.EventEmitter(event_queue, watch, timeout=1)
watchdog.observers.api.EventDispatcher(timeout=1)
watchdog.observers.api.BaseObserver(emitter_class, timeout=1)
'''


logger = logging.getLogger('sync')
logger.setLevel(logging.DEBUG)
rotatinghandler = logging.handlers.RotatingFileHandler('sync.log', mode='a', 
                                                       maxBytes=1024*1024, 
                                                       backupCount=4,
                                                       encoding='utf-8',
                                                       )
rotatinghandler.setLevel(logging.DEBUG)
rotatinghandler.setFormatter(logging.Formatter(
                            '%(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(rotatinghandler)


def file_to_watch():
    with open('config.json', 'r', encoding='utf-8') as f:
        config = json.load(f)
        # such as 'Linux', 'Darwin', 'Java', 'Windows'. 
        # An empty string is returned if the value cannot be determined
        system = platform.system()
        if system == 'Windows':
            return config['windows']
        elif system == 'Linux':
            fd = os.popen('ps -A |grep -i "gnome|kde|mate|cinnamon|lx|xfce|jwm"')
            if fd.read() == '':
                return config['linux-server']
            else:
                return config['linux-desktop']
        else:
            logger.error('不支持的系统')
            sys.exit(-1)


class copyHandler(FileSystemEventHandler):
    def __init__(self):
        FileSystemEventHandler.__init__(self)
        self.ob_files = {}

    def set_config(self, config):
        self.ob_files = config

    def on_open(self, event):
        logger.info(event.src_path)

    def on_modified(self, event):
        if event.src_path == self.ob_files['src']:
            if self.ob_files['op'] == 'copy':
                shutil.copy(event.src_path, self.ob_files['dst'])
                logger.info(event.src_path+' 文件备份成功 ' + 
                            self.ob_files['dst'])
            elif self.ob_files['op'] == 'reload':
                # 自举
                try:
                    # os.fsync()
                    logger.debug('配置文件['+event.src_path+']有更新，重启应用'+__file__)
                    os.execv(__file__, sys.argv)
                except Exception as e:
                    logger.error(e)
                    time.sleep(3)

    def on_close(self, event):
        if event.src_path in list(self.ob_files):
            logger.info(event.src_path+' 关闭了')


if __name__ == "__main__":

    configjson = os.getcwd()+'\\config.json'
    logger.debug("CONFIG_JSON: "+configjson)
    conf = {
        'src': configjson,
        'dst': configjson,
        'op': 'reload'
    }
    configs = file_to_watch()
    # watch the config.json, dynamic load
    configs.append(conf)

    ob = Observer()
    for c in configs:
        src = c['src']
        dst = c['dst']

        event_handler = copyHandler()
        event_handler.set_config(c)
        ob.schedule(event_handler, os.path.split(src)[0], recursive=False)

    try:
        ob.start()
        while True:
            time.sleep(1)
    finally:
        ob.stop()
        ob.join()